package org.zebra.mybatis.plus.ext.datapermission;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
import com.baomidou.mybatisplus.extension.plugins.handler.DataPermissionHandler;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import org.zebra.mybatis.plus.ext.datapermission.annotation.DataPermission;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 数据权限拦截器
 *
 * @author zhanghongbin
 */
@Slf4j
public class DataPermissionHandlerImpl implements DataPermissionHandler {

    // 方法或类(名称) 与 注解的映射关系缓存
    private final Map<String, Dict> dataPermissionCacheMap = new ConcurrentHashMap<>();

    @Override
    public Expression getSqlSegment(Expression where, String mappedStatementId) {
        if (InterceptorIgnoreHelper.willIgnoreDataPermission(mappedStatementId)) {
            return where;
        }

        Dict dict = this.findDataPermission(mappedStatementId);
        if (ObjectUtil.isNull(dict)) {
            return where;
        }
        DataPermission dataPermission = (DataPermission) dict.get("dataPermission");
        Method method = (Method) dict.get("method");
        try {
            DataPermissionRule dataPermissionRule = SpringUtil.getBean(dataPermission.value());
            Expression expression = dataPermissionRule.getExpression(method);
            if (expression != null) {
                return null != where ? new AndExpression(where, new Parenthesis(expression)) : expression;
            }
        } catch (Exception e) {
            log.error("数据权限 " + dataPermission.value().getClass().getName(), e);
        }
        return where;
    }

    private Dict findDataPermission(String mappedStatementId) {
        StringBuilder sb = new StringBuilder(mappedStatementId);
        int index = sb.lastIndexOf(".");
        String clazzName = sb.substring(0, index);
        String methodName = sb.substring(index + 1, sb.length());
        Class<?> clazz;
        try {
            clazz = ClassUtil.loadClass(clazzName);
        } catch (Exception e) {
            return null;
        }
        List<Method> methods = Arrays.stream(ClassUtil.getDeclaredMethods(clazz))
                .filter(method -> method.getName().equals(methodName))
                .collect(Collectors.toList());
        Dict dict;
        // 获取方法注解
        for (Method method : methods) {
            dict = dataPermissionCacheMap.get(mappedStatementId);
            if (ObjectUtil.isNotNull(dict)) {
                return dict;
            }
            if (AnnotationUtil.hasAnnotation(method, DataPermission.class)) {
                DataPermission dataPermission = AnnotationUtil.getAnnotation(method, DataPermission.class);
                dict = Dict.create();
                dict.set("dataPermission", dataPermission);
                dict.set("method", method);
                dataPermissionCacheMap.put(mappedStatementId, dict);
                return dict;
            }
        }
        return null;
    }
}
